﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI.Selection;
using YArchitech.LIB;
using YArchitech.Revit;

namespace YArchitech.HVAC
{
	public class CoilFanConnHelper
	{
		public CoilFanConnHelper(Autodesk.Revit.DB.Document doc, Selection sel)
		{
			this.Doc = doc;
			this.Sel = sel;
		}

		public void SelectElementSet()
		{
			IList<Element> list = this.Sel.PickElementsByRectangle(new CoilFanSelectionFilter(), "请选择需要连接的风机盘管……");
			while (list == null || list.Count < 1)
			{
				list = this.Sel.PickElementsByRectangle(new CoilFanSelectionFilter(), "请选择需要连接的风机盘管……");
			}
			this.listCoilFan = new List<FamilyInstance>();
			foreach (Element element in list)
			{
				this.listCoilFan.Add(element as FamilyInstance);
			}
			Reference reference;
            for (reference = this.Sel.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, new YJKCurveLineFilter(), "请选择路由线路的起始端（选择点近的一段为起始端）……"); reference == null; reference = this.Sel.PickObject((ObjectType)1, new YJKCurveLineFilter(), "请选择路由线路的起始端（选择点近的一段为起始端）……"))
			{
			}
			SearchCurve searchCurve = new SearchCurve(this.doc.GetElement(reference) as CurveElement, reference.GlobalPoint, 0.032808398950131233);
			searchCurve.DoSearch();
			this.rootNode = searchCurve.GetListRoot();
			this.rootNode = this.rootNode.AnalysisCurveNode(this.rootNode);
		}

		public bool CreatConnCoilPipes()
		{
			bool result = true;
			List<FamilyInstanceToCurves> list = this.DetermineFamilyIntance();
			if (list == null || list.Count < 1)
			{
				throw new Exception("连接位置不合适。");
			}
			list = this.ConfirmFIToCurve(list);
			if (list == null || list.Count < 1)
			{
				throw new Exception("风盘连接口延长点在路由上没有投影点，不能进行连接。");
			}
			List<CurveToFamilyInstances> ctfiSet = new List<CurveToFamilyInstances>();
			this.ConfirmReference(list, this.rootNode, ref ctfiSet);
			XYZ vector = this.GetDeviateVector(ctfiSet) * -1.0;
			List<YJKLine> listNode = null;
			this.GetHYLinesByElemNode(this.rootNode, ref listNode);
			List<YJKLine> pipeLineSet = this.GetPipeLineSet(listNode, (double)this.CoilConnSet.SupplyDistance / 304.8, vector);
			List<YJKLine> pipeLineSet2 = this.GetPipeLineSet(pipeLineSet, (double)this.CoilConnSet.ReturnDistance / 304.8, vector);
			List<YJKLine> pipeLineSet3 = this.GetPipeLineSet(pipeLineSet2, (double)this.CoilConnSet.SanitaryDistance / 304.8, vector);
			List<Connector> elementConnector = YJKRevitTools.GetElementConnector(this.listCoilFan[0], (Autodesk.Revit.DB.Domain)3);
			List<Pipe> list2 = null;
			List<Pipe> list3 = null;
			List<Pipe> list4 = null;
			SubTransaction subTransaction = new SubTransaction(this.Doc);
			try
			{
				subTransaction.Start();
				foreach (Connector connector in elementConnector)
				{
					PipeSystemType pipeSystemType = connector.PipeSystemType;
                    if ((int)pipeSystemType != 7)
					{
                        if ((int)pipeSystemType != 8)
						{
							list4 = this.CreatPipeByTrack(pipeLineSet3, 3);
						}
						else
						{
							list3 = this.CreatPipeByTrack(pipeLineSet2, 2);
						}
					}
					else
					{
						list2 = this.CreatPipeByTrack(pipeLineSet, 1);
					}
				}
				this.CtFamilys = ctfiSet;
				this.supplyPipes = list2;
				this.returnPipes = list3;
				this.sanitaryPipes = list4;
				subTransaction.Commit();
			}
			catch (Exception)
			{
				result = false;
				subTransaction.RollBack();
			}
			return result;
		}

		public bool ConnCoilsAndPipes()
		{
			bool result = true;
			for (int i = 0; i < this.CtFamilys.Count; i++)
			{
				CurveToFamilyInstances curveToFamilyInstances = this.CtFamilys[i];
				List<FamilyInstance> familyInstances = curveToFamilyInstances.FamilyInstances;
				if (familyInstances != null && familyInstances.Count > 0)
				{
					IList<Pipe> list = new List<Pipe>();
					if (this.SupplyPipes != null && this.SupplyPipes.Count > 0)
					{
						list.Add(this.SupplyPipes[i]);
					}
					if (this.ReturnPipes != null && this.ReturnPipes.Count > 0)
					{
						list.Add(this.ReturnPipes[i]);
					}
					if (this.SanitaryPipes != null && this.SanitaryPipes.Count > 0)
					{
						list.Add(this.SanitaryPipes[i]);
					}
					new YJKRotateFamilyInstance();
					if (list.Count > 0)
					{
						result = this.ConnCoilsAndPipes(list, familyInstances, curveToFamilyInstances.CurveNode.PointIn);
					}
				}
			}
			return result;
		}

		private bool ConnCoilsAndPipes(IList<Pipe> pipes, IList<FamilyInstance> listFI, XYZ basePnt)
		{
			HYPipeConnect hypipeConnect = new HYPipeConnect();
			if (listFI == null || listFI.Count < 1)
			{
				return false;
			}
			bool result;
			if (listFI.Count == 1)
			{
				result = hypipeConnect.BeathchConnPipeEquipment(ref pipes, listFI.ToList<Element>(), 1, basePnt, this.FSymbols, this.bFlex, this.flexLength);
			}
			else
			{
				result = hypipeConnect.BeathchConnPipeEquipment(ref pipes, listFI.ToList<Element>(), 1, basePnt, this.FSymbols, this.bFlex, this.flexLength);
			}
			this.Doc.Regenerate();
			return result;
		}

		private List<Pipe> CreatPipeByTrack(List<YJKLine> trackLines, int ptNum)
		{
			if (trackLines == null || trackLines.Count < 1)
			{
				return null;
			}
			List<Pipe> list = new List<Pipe>();
			PipingSystemType pipingSystemType = null;
			PipeType pipeType = null;
			double diameter = 0.0;
			double num = 0.0;
			Level genLevel = this.doc.ActiveView.GenLevel;
			switch (ptNum)
			{
			case 1:
				pipingSystemType = (this.doc.GetElementById(this.ConnectorSetId.SupplySysId) as PipingSystemType);
				pipeType = (this.doc.GetElementById(this.ConnectorSetId.SupplyPipeTypeId) as PipeType);
				diameter = (double)this.CoilConnSet.SupplyDiameter;
				num = genLevel.ProjectElevation + this.CoilConnSet.SupplyOffset * 1000.0 / 304.8;
				break;
			case 2:
				pipingSystemType = (this.doc.GetElementById(this.ConnectorSetId.ReturnSysId) as PipingSystemType);
				pipeType = (this.doc.GetElementById(this.ConnectorSetId.ReturnPipeTypeId) as PipeType);
				diameter = (double)this.CoilConnSet.ReturnDiameter;
				num = genLevel.ProjectElevation + this.CoilConnSet.ReturnOffset * 1000.0 / 304.8;
				break;
			case 3:
				pipingSystemType = (this.doc.GetElementById(this.ConnectorSetId.SanitarySysId) as PipingSystemType);
				pipeType = (this.doc.GetElementById(this.ConnectorSetId.SanitaryPipeTypeId) as PipeType);
				diameter = (double)this.CoilConnSet.SanitaryDiameter;
				num = genLevel.ProjectElevation + this.CoilConnSet.SanitaryOffset * 1000.0 / 304.8;
				break;
			}
			foreach (YJKLine hyline in trackLines)
			{
				XYZ xyz = hyline.StartPoint;
				XYZ xyz2 = hyline.EndPoint;
				xyz = new XYZ(xyz.X, xyz.Y, num);
				xyz2 = new XYZ(xyz2.X, xyz2.Y, num);
				Pipe item = this.doc.CreatHYPipe(pipingSystemType, pipeType, genLevel, xyz, xyz2, diameter);
				this.doc.Regenerate();
				list.Add(item);
			}
			HYPipeConnect hypipeConnect = new HYPipeConnect();
			if (list.Count > 1)
			{
				for (int i = 0; i < list.Count - 1; i++)
				{
					Pipe item2 = list[i];
					Pipe item3 = list[i + 1];
					hypipeConnect.NewElbowFitting(new List<Pipe>
					{
						item2,
						item3
					}, true);
					this.Doc.Regenerate();
				}
			}
			return list;
		}

		private XYZ GetDeviateVector(List<CurveToFamilyInstances> ctfiSet)
		{
			XYZ result = null;
			foreach (CurveToFamilyInstances curveToFamilyInstances in ctfiSet)
			{
				if (curveToFamilyInstances.FamilyInstances != null && curveToFamilyInstances.FamilyInstances.Count > 0)
				{
					Connector fanConnector = this.GetFanConnector(curveToFamilyInstances.FamilyInstances[0], 1);
					XYZ xyz = fanConnector.Origin.Add(fanConnector.CoordinateSystem.BasisZ * this.SupplyLength);
					CurveElementNode curveNode = curveToFamilyInstances.CurveNode;
					XYZ project = new YJKLine(curveNode.PointIn, curveNode.PointOut).GetProject(xyz);
					xyz = new XYZ(xyz.X, xyz.Y, project.Z);
					XYZ xyz2 = xyz.Subtract(project).Normalize();
					result = curveNode.PointIn.Subtract(curveNode.PointOut).Normalize().CrossProduct(xyz2).Normalize() * -1.0;
					break;
				}
			}
			return result;
		}

		private void GetHYLinesByElemNode(CurveElementNode rootNode, ref List<YJKLine> lineList)
		{
			if (rootNode == null)
			{
				return;
			}
			if (lineList == null)
			{
				lineList = new List<YJKLine>();
			}
			lineList.Add(new YJKLine(rootNode.PointIn, rootNode.PointOut));
			if (rootNode.Next != null)
			{
				this.GetHYLinesByElemNode(rootNode.Next, ref lineList);
			}
		}

		private List<YJKLine> GetPipeLineSet(List<YJKLine> listNode, double distance, XYZ vector)
		{
			List<YJKLine> list = new List<YJKLine>();
			IList<YJKLine> moveTrackLines = this.GetMoveTrackLines(listNode, distance, vector);
			IList<XYZ> trackPoints = this.GetTrackPoints(moveTrackLines, listNode);
			if (trackPoints != null && trackPoints.Count >= 2)
			{
				for (int i = 0; i < trackPoints.Count - 1; i++)
				{
					list.Add(new YJKLine(trackPoints[i], trackPoints[i + 1]));
				}
			}
			return list;
		}

		private IList<YJKLine> GetMoveTrackLines(List<YJKLine> listNode, double distance, XYZ vector)
		{
			IList<YJKLine> list = new List<YJKLine>();
			if (listNode.Count < 1)
			{
				return list;
			}
			foreach (YJKLine hyLine in listNode)
			{
				list.Add(this.GetMoveLine(hyLine, distance, vector));
			}
			return list;
		}

		private IList<XYZ> GetTrackPoints(IList<YJKLine> listLine, IList<YJKLine> listNode)
		{
			IList<XYZ> list = new List<XYZ>();
			if (listLine == null || listLine.Count < 1)
			{
				return list;
			}
			if (listLine.Count == 1)
			{
				YJKLine hyline = new YJKLine(listLine[0].StartPoint, listLine[0].EndPoint);
				hyline.MakeUnBound();
				XYZ item = hyline.GetProject(listNode[0].StartPoint);
				list.Add(item);
				item = hyline.GetProject(listNode[0].EndPoint);
				list.Add(item);
			}
			else
			{
				double num = (double)listLine.Count;
				int num2 = 0;
				XYZ item;
				while ((double)(num2 + 1) < num)
				{
					YJKLine hyline2 = new YJKLine(listLine[num2].StartPoint, listLine[num2].EndPoint);
					YJKLine hyline3 = new YJKLine(listLine[num2 + 1].StartPoint, listLine[num2 + 1].EndPoint);
					if (num2 == 0)
					{
						item = hyline2.GetProject(listNode[0].StartPoint);
						list.Add(item);
					}
					item = hyline2.IntersectionPoint(hyline3.Line, true);
					list.Add(item);
					num2++;
				}
				YJKLine hyline4 = new YJKLine(listLine.Last<YJKLine>().StartPoint, listLine.Last<YJKLine>().EndPoint);
				hyline4.MakeUnBound();
				item = hyline4.GetProject(listNode.Last<YJKLine>().EndPoint);
				list.Add(item);
			}
			return list;
		}

		private YJKLine GetMoveLine(YJKLine hyLine, double distance, XYZ vector)
		{
			XYZ xyz = hyLine.StartPoint;
			XYZ xyz2 = hyLine.EndPoint;
			XYZ xyz3 = xyz2.Subtract(xyz).Normalize().CrossProduct(vector).Normalize() * distance;
			xyz = xyz.Add(xyz3);
			xyz2 = xyz2.Add(xyz3);
			return new YJKLine(xyz, xyz2);
		}

		private List<FamilyInstanceToCurves> DetermineFamilyIntance()
		{
			List<FamilyInstanceToCurves> list = new List<FamilyInstanceToCurves>();
			foreach (FamilyInstance fi in this.listCoilFan)
			{
				FamilyInstanceToCurves item = null;
				this.JudgeCurveNodes(fi, this.rootNode, ref item);
				list.Add(item);
			}
			return list;
		}

		private List<FamilyInstanceToCurves> ConfirmFIToCurve(List<FamilyInstanceToCurves> fiToCurveses)
		{
			List<FamilyInstanceToCurves> list = new List<FamilyInstanceToCurves>();
			foreach (FamilyInstanceToCurves familyInstanceToCurves in fiToCurveses)
			{
				FamilyInstanceToCurves familyInstanceToCurves2 = new FamilyInstanceToCurves();
				familyInstanceToCurves2.FInstance = familyInstanceToCurves.FInstance;
				familyInstanceToCurves2.NodeSet = new List<CurveElementNode>();
				if (familyInstanceToCurves.NodeSet.Count == 1)
				{
					familyInstanceToCurves2.NodeSet.Add(familyInstanceToCurves.NodeSet[0]);
					list.Add(familyInstanceToCurves2);
				}
				else if (familyInstanceToCurves.NodeSet.Count > 1)
				{
					Connector fanConnector = this.GetFanConnector(familyInstanceToCurves.FInstance, 1);
					XYZ xyz = fanConnector.Origin.Add(fanConnector.CoordinateSystem.BasisZ * this.SupplyLength);
					double num = 0.0;
					CurveElementNode item = null;
					for (int i = 0; i < familyInstanceToCurves.NodeSet.Count; i++)
					{
						CurveElementNode curveElementNode = familyInstanceToCurves.NodeSet[i];
						double num2 = new YJKLine(curveElementNode.PointIn, curveElementNode.PointOut).GetProject(xyz).DistanceTo(xyz);
						if (i == 0)
						{
							num = num2;
							item = curveElementNode;
						}
						else if (num > num2)
						{
							num = num2;
							item = curveElementNode;
						}
					}
					familyInstanceToCurves2.NodeSet.Add(item);
					list.Add(familyInstanceToCurves2);
				}
			}
			return list;
		}

		private void ConfirmReference(List<FamilyInstanceToCurves> fiToCurveses, CurveElementNode rootNode, ref List<CurveToFamilyInstances> ctfiSet)
		{
			if (rootNode == null)
			{
				return;
			}
			CurveToFamilyInstances curveToFamilyInstances = new CurveToFamilyInstances();
			curveToFamilyInstances.CurveNode = rootNode;
			curveToFamilyInstances.FamilyInstances = new List<FamilyInstance>();
			foreach (FamilyInstanceToCurves familyInstanceToCurves in fiToCurveses)
			{
				if (familyInstanceToCurves.NodeSet[0].CurveElement.Id == rootNode.CurveElement.Id)
				{
					curveToFamilyInstances.FamilyInstances.Add(familyInstanceToCurves.FInstance);
				}
			}
			ctfiSet.Add(curveToFamilyInstances);
			if (rootNode.Next != null)
			{
				this.ConfirmReference(fiToCurveses, rootNode.Next, ref ctfiSet);
			}
		}

		private Connector GetFanConnector(FamilyInstance fi, int connTypeNum)
		{
			ConnectHelper connectHelper = new ConnectHelper();
			Connector result = null;
			foreach (Connector connector in connectHelper.GetYJKElementConnector(fi, (Autodesk.Revit.DB.Domain)3))
			{
				switch (connTypeNum)
				{
				case 1:
					if ((int)connector.PipeSystemType == 7)
					{
						result = connector;
					}
					break;
				case 2:
					if ((int)connector.PipeSystemType == 8)
					{
						result = connector;
					}
					break;
				case 3:
					if ((int)connector.PipeSystemType == 22 || (int)connector.PipeSystemType == 16)
					{
						result = connector;
					}
					break;
				}
			}
			return result;
		}

		private bool JudgePointOnCurveNode(XYZ point, CurveElementNode curveNode)
		{
			bool result = false;
			YJKLine hyline = new YJKLine(curveNode.PointIn, curveNode.PointOut);
			hyline.MakeUnBound();
			XYZ project = hyline.GetProject(point);
			if (hyline.IsPointOnLine(project))
			{
				result = true;
			}
			return result;
		}

		private void JudgeCurveNodes(FamilyInstance fi, CurveElementNode rootNode, ref FamilyInstanceToCurves fitCurve)
		{
			if (fi == null || rootNode == null)
			{
				return;
			}
			if (fitCurve == null)
			{
				fitCurve = new FamilyInstanceToCurves();
				fitCurve.FInstance = fi;
				fitCurve.NodeSet = new List<CurveElementNode>();
			}
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			Connector fanConnector = this.GetFanConnector(fi, 1);
			if (fanConnector != null)
			{
				XYZ point = fanConnector.Origin.Add(fanConnector.CoordinateSystem.BasisZ * this.SupplyLength);
				flag = this.JudgePointOnCurveNode(point, rootNode);
			}
			fanConnector = this.GetFanConnector(fi, 1);
			if (fanConnector != null)
			{
				XYZ point = fanConnector.Origin.Add(fanConnector.CoordinateSystem.BasisZ * this.ReturnLength);
				flag2 = this.JudgePointOnCurveNode(point, rootNode);
			}
			fanConnector = this.GetFanConnector(fi, 1);
			if (fanConnector != null)
			{
				XYZ point = fanConnector.Origin.Add(fanConnector.CoordinateSystem.BasisZ * this.SanitaryLength);
				flag3 = this.JudgePointOnCurveNode(point, rootNode);
			}
			if (flag && flag2 && flag3)
			{
				fitCurve.NodeSet.Add(rootNode);
			}
			if (rootNode.Next != null)
			{
				this.JudgeCurveNodes(fi, rootNode.Next, ref fitCurve);
			}
		}

		public Document Doc
		{
			get
			{
				return this.doc;
			}
			set
			{
				this.doc = value;
			}
		}

		public Selection Sel
		{
			get
			{
				return this.sel;
			}
			set
			{
				this.sel = value;
			}
		}

		public List<FamilySymbol> FSymbols
		{
			get
			{
				return this.fSymbols;
			}
			set
			{
				this.fSymbols = value;
			}
		}

		public double SupplyLength
		{
			get
			{
				return this.supplyLength;
			}
			set
			{
				this.supplyLength = value;
			}
		}

		public double ReturnLength
		{
			get
			{
				return this.returnLength;
			}
			set
			{
				this.returnLength = value;
			}
		}

		public double SanitaryLength
		{
			get
			{
				return this.sanitaryLength;
			}
			set
			{
				this.sanitaryLength = value;
			}
		}

		public CoilTrackConn CoilConnSet
		{
			get
			{
				return this.coilConnSet;
			}
			set
			{
				this.coilConnSet = value;
			}
		}

		public HYConnSetId ConnectorSetId
		{
			get
			{
				return this.connectorSetId;
			}
			set
			{
				this.connectorSetId = value;
			}
		}

		public List<CurveToFamilyInstances> CtFamilys
		{
			get
			{
				return this.ctFamilys;
			}
			set
			{
				this.ctFamilys = value;
			}
		}

		public List<Pipe> SupplyPipes
		{
			get
			{
				return this.supplyPipes;
			}
			set
			{
				this.supplyPipes = value;
			}
		}

		public List<Pipe> ReturnPipes
		{
			get
			{
				return this.returnPipes;
			}
			set
			{
				this.returnPipes = value;
			}
		}

		public List<Pipe> SanitaryPipes
		{
			get
			{
				return this.sanitaryPipes;
			}
			set
			{
				this.sanitaryPipes = value;
			}
		}

		public bool BFlex
		{
			get
			{
				return this.bFlex;
			}
			set
			{
				this.bFlex = value;
			}
		}

		public double FlexLength
		{
			get
			{
				return this.flexLength;
			}
			set
			{
				this.flexLength = value;
			}
		}

		private Document doc;

		private Selection sel;

		private IList<FamilyInstance> listCoilFan;

		private List<FamilySymbol> fSymbols;

		private double supplyLength;

		private double returnLength;

		private double sanitaryLength;

		private CoilTrackConn coilConnSet;

		private HYConnSetId connectorSetId;

		private CurveElementNode rootNode;

		private List<CurveToFamilyInstances> ctFamilys;

		private List<Pipe> supplyPipes;

		private List<Pipe> returnPipes;

		private List<Pipe> sanitaryPipes;

		private bool bFlex;

		private double flexLength;
	}
}
